package com.coupon.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.coupon.admin.dto.CouponCreateDTO;
import com.coupon.admin.dto.CouponUpdateDTO;
import com.coupon.admin.dto.CouponQueryDTO;
import com.coupon.admin.entity.Coupon;
import com.coupon.admin.mapper.CouponMapper;
import com.coupon.admin.service.CouponService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 优惠券服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements CouponService {
    
    private final ObjectMapper objectMapper;
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createCoupon(CouponCreateDTO createDTO) {
        // 参数校验
        validateCouponCreate(createDTO);
        
        Coupon coupon = new Coupon();
        BeanUtils.copyProperties(createDTO, coupon);
        
        // 设置默认值
        coupon.setStatus("DRAFT");
        coupon.setIssuedCount(0);
        coupon.setReceivedCount(0);
        coupon.setUsedCount(0);
        
        // 处理适用范围ID列表
        if (!CollectionUtils.isEmpty(createDTO.getScopeIds())) {
            try {
                coupon.setScopeIds(objectMapper.writeValueAsString(createDTO.getScopeIds()));
            } catch (JsonProcessingException e) {
                log.error("序列化适用范围ID列表失败", e);
                throw new RuntimeException("适用范围ID列表格式错误");
            }
        }
        
        // 保存优惠券
        save(coupon);
        
        log.info("创建优惠券成功，ID: {}, 名称: {}", coupon.getId(), coupon.getName());
        return coupon.getId();
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCoupon(Long id, CouponUpdateDTO updateDTO) {
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new RuntimeException("优惠券不存在");
        }
        
        // 只有草稿状态的券才能编辑
        if (!"DRAFT".equals(coupon.getStatus())) {
            throw new RuntimeException("只有草稿状态的优惠券才能编辑");
        }
        
        // 更新字段
        if (StringUtils.hasText(updateDTO.getName())) {
            coupon.setName(updateDTO.getName());
        }
        if (updateDTO.getValue() != null) {
            coupon.setValue(updateDTO.getValue());
        }
        if (updateDTO.getThreshold() != null) {
            coupon.setThreshold(updateDTO.getThreshold());
        }
        if (updateDTO.getTotalStock() != null) {
            coupon.setTotalStock(updateDTO.getTotalStock());
        }
        if (updateDTO.getPerUserLimit() != null) {
            coupon.setPerUserLimit(updateDTO.getPerUserLimit());
        }
        if (updateDTO.getValidStartTime() != null) {
            coupon.setValidStartTime(updateDTO.getValidStartTime());
        }
        if (updateDTO.getValidEndTime() != null) {
            coupon.setValidEndTime(updateDTO.getValidEndTime());
        }
        if (StringUtils.hasText(updateDTO.getScope())) {
            coupon.setScope(updateDTO.getScope());
        }
        if (!CollectionUtils.isEmpty(updateDTO.getScopeIds())) {
            try {
                coupon.setScopeIds(objectMapper.writeValueAsString(updateDTO.getScopeIds()));
            } catch (JsonProcessingException e) {
                log.error("序列化适用范围ID列表失败", e);
                throw new RuntimeException("适用范围ID列表格式错误");
            }
        }
        if (StringUtils.hasText(updateDTO.getDescription())) {
            coupon.setDescription(updateDTO.getDescription());
        }
        if (StringUtils.hasText(updateDTO.getUsageInstructions())) {
            coupon.setUsageInstructions(updateDTO.getUsageInstructions());
        }
        if (updateDTO.getSupportGroup() != null) {
            coupon.setSupportGroup(updateDTO.getSupportGroup());
        }
        if (updateDTO.getGroupSize() != null) {
            coupon.setGroupSize(updateDTO.getGroupSize());
        }
        if (updateDTO.getGroupRewardMultiplier() != null) {
            coupon.setGroupRewardMultiplier(updateDTO.getGroupRewardMultiplier());
        }
        if (updateDTO.getSupportBlindBox() != null) {
            coupon.setSupportBlindBox(updateDTO.getSupportBlindBox());
        }
        if (updateDTO.getBlindBoxTaskId() != null) {
            coupon.setBlindBoxTaskId(updateDTO.getBlindBoxTaskId());
        }
        if (StringUtils.hasText(updateDTO.getLadderConfig())) {
            coupon.setLadderConfig(updateDTO.getLadderConfig());
        }
        if (updateDTO.getAiWeight() != null) {
            coupon.setAiWeight(updateDTO.getAiWeight());
        }
        
        boolean result = updateById(coupon);
        log.info("更新优惠券成功，ID: {}", id);
        return result;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean publishCoupon(Long id) {
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new RuntimeException("优惠券不存在");
        }
        
        if (!"DRAFT".equals(coupon.getStatus())) {
            throw new RuntimeException("只有草稿状态的优惠券才能发布");
        }
        
        // 校验有效期
        if (coupon.getValidEndTime().isBefore(LocalDateTime.now())) {
            throw new RuntimeException("优惠券有效期已过期，无法发布");
        }
        
        coupon.setStatus("PUBLISHED");
        boolean result = updateById(coupon);
        
        log.info("发布优惠券成功，ID: {}", id);
        return result;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean stopCoupon(Long id) {
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new RuntimeException("优惠券不存在");
        }
        
        if (!"PUBLISHED".equals(coupon.getStatus())) {
            throw new RuntimeException("只有已发布状态的优惠券才能停用");
        }
        
        coupon.setStatus("STOPPED");
        boolean result = updateById(coupon);
        
        log.info("停用优惠券成功，ID: {}", id);
        return result;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteCoupon(Long id) {
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new RuntimeException("优惠券不存在");
        }
        
        if (!"DRAFT".equals(coupon.getStatus())) {
            throw new RuntimeException("只有草稿状态的优惠券才能删除");
        }
        
        boolean result = removeById(id);
        log.info("删除优惠券成功，ID: {}", id);
        return result;
    }
    
    @Override
    public IPage<Coupon> getCouponPage(Page<Coupon> page, CouponQueryDTO queryDTO) {
        LambdaQueryWrapper<Coupon> wrapper = new LambdaQueryWrapper<>();
        
        if (StringUtils.hasText(queryDTO.getName())) {
            wrapper.like(Coupon::getName, queryDTO.getName());
        }
        if (StringUtils.hasText(queryDTO.getType())) {
            wrapper.eq(Coupon::getType, queryDTO.getType());
        }
        if (StringUtils.hasText(queryDTO.getStatus())) {
            wrapper.eq(Coupon::getStatus, queryDTO.getStatus());
        }
        if (StringUtils.hasText(queryDTO.getScope())) {
            wrapper.eq(Coupon::getScope, queryDTO.getScope());
        }
        if (queryDTO.getMerchantId() != null) {
            wrapper.eq(Coupon::getMerchantId, queryDTO.getMerchantId());
        }
        if (queryDTO.getValidStartTime() != null) {
            wrapper.ge(Coupon::getValidStartTime, queryDTO.getValidStartTime());
        }
        if (queryDTO.getValidEndTime() != null) {
            wrapper.le(Coupon::getValidEndTime, queryDTO.getValidEndTime());
        }
        if (queryDTO.getSupportGroup() != null) {
            wrapper.eq(Coupon::getSupportGroup, queryDTO.getSupportGroup());
        }
        if (queryDTO.getSupportBlindBox() != null) {
            wrapper.eq(Coupon::getSupportBlindBox, queryDTO.getSupportBlindBox());
        }
        
        wrapper.orderByDesc(Coupon::getCreateTime);
        
        return page(page, wrapper);
    }
    
    @Override
    public Coupon getCouponDetail(Long id) {
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new RuntimeException("优惠券不存在");
        }
        return coupon;
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchOperateCoupons(List<Long> ids, String operation) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new RuntimeException("请选择要操作的优惠券");
        }
        
        switch (operation) {
            case "publish":
                return batchPublishCoupons(ids);
            case "stop":
                return batchStopCoupons(ids);
            case "delete":
                return batchDeleteCoupons(ids);
            default:
                throw new RuntimeException("不支持的操作类型");
        }
    }
    
    @Override
    public Object getCouponEffectAnalysis(Long couponId) {
        Coupon coupon = getById(couponId);
        if (coupon == null) {
            throw new RuntimeException("优惠券不存在");
        }
        
        // 计算核心指标
        double receiveRate = coupon.getTotalStock() > 0 ? 
            (double) coupon.getReceivedCount() / coupon.getTotalStock() : 0;
        double useRate = coupon.getReceivedCount() > 0 ? 
            (double) coupon.getUsedCount() / coupon.getReceivedCount() : 0;
        
        return new Object() {
            public final Long couponId = coupon.getId();
            public final String name = coupon.getName();
            public final Integer totalStock = coupon.getTotalStock();
            public final Integer receivedCount = coupon.getReceivedCount();
            public final Integer usedCount = coupon.getUsedCount();
            public final Double receiveRate = receiveRate;
            public final Double useRate = useRate;
            public final BigDecimal totalDiscount = coupon.getValue().multiply(BigDecimal.valueOf(coupon.getUsedCount()));
        };
    }
    
    @Override
    public boolean canEditCoupon(Long id) {
        Coupon coupon = getById(id);
        return coupon != null && "DRAFT".equals(coupon.getStatus());
    }
    
    @Override
    public boolean updateAiWeight(Long id, Double weight) {
        Coupon coupon = getById(id);
        if (coupon == null) {
            throw new RuntimeException("优惠券不存在");
        }
        
        coupon.setAiWeight(BigDecimal.valueOf(weight));
        return updateById(coupon);
    }
    
    /**
     * 校验优惠券创建参数
     */
    private void validateCouponCreate(CouponCreateDTO createDTO) {
        if (createDTO.getValidEndTime().isBefore(createDTO.getValidStartTime())) {
            throw new RuntimeException("有效期结束时间不能早于开始时间");
        }
        
        if (createDTO.getValidEndTime().isBefore(LocalDateTime.now())) {
            throw new RuntimeException("有效期结束时间不能早于当前时间");
        }
        
        // 阶梯券特殊校验
        if ("LADDER".equals(createDTO.getType()) && !StringUtils.hasText(createDTO.getLadderConfig())) {
            throw new RuntimeException("阶梯券必须配置阶梯规则");
        }
        
        // 拼券团特殊校验
        if (Boolean.TRUE.equals(createDTO.getSupportGroup())) {
            if (createDTO.getGroupSize() == null || createDTO.getGroupSize() < 2) {
                throw new RuntimeException("拼券团人数至少需要2人");
            }
        }
    }
    
    /**
     * 批量发布优惠券
     */
    private boolean batchPublishCoupons(List<Long> ids) {
        LambdaQueryWrapper<Coupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Coupon::getId, ids).eq(Coupon::getStatus, "DRAFT");
        
        Coupon updateCoupon = new Coupon();
        updateCoupon.setStatus("PUBLISHED");
        
        return update(updateCoupon, wrapper);
    }
    
    /**
     * 批量停用优惠券
     */
    private boolean batchStopCoupons(List<Long> ids) {
        LambdaQueryWrapper<Coupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Coupon::getId, ids).eq(Coupon::getStatus, "PUBLISHED");
        
        Coupon updateCoupon = new Coupon();
        updateCoupon.setStatus("STOPPED");
        
        return update(updateCoupon, wrapper);
    }
    
    /**
     * 批量删除优惠券
     */
    private boolean batchDeleteCoupons(List<Long> ids) {
        LambdaQueryWrapper<Coupon> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(Coupon::getId, ids).eq(Coupon::getStatus, "DRAFT");
        
        return remove(wrapper);
    }
}
